#pragma once
#include<iostream>
#include<etcd/Client.hpp>
#include<etcd/KeepAlive.hpp>
#include<etcd/Response.hpp>
#include<etcd/Watcher.hpp>
#include<etcd/Value.hpp>
#include"logger.hpp"
//etcd是一个键值对存储系统
//这个文件对etcd的增和查进行了封装
//实现通过[服务名字-服务url]增添数据
//通过[etcd服务url,查询根目录,上线的回调函数，下线的回调函数]对etcd的数据进行监控
namespace zzy_mims
{
class Registery
{
public:
    using ptr = std::shared_ptr<Registery>;
    Registery(const std::string& host):
    _client(std::make_shared<etcd::Client>(host)),
    _keep_alive(_client->leasekeepalive(3).get()),
    _lease_id(_keep_alive->Lease()){};

    ~Registery(){_keep_alive->Cancel();};

    bool Register(const std::string& key,const std::string& value)
    {
        auto resp = _client->put(key,value,_lease_id).get();
        if (resp.is_ok() == false)
        {
            LOG_ERROR("注册数据失败,{}\n",resp.error_message());
            return false;
        }
        return true;
    }
private:
    std::shared_ptr<etcd::Client> _client;
    std::shared_ptr<etcd::KeepAlive> _keep_alive;
    uint64_t _lease_id;
};
class Discovery
{
public:
    using ptr = std::shared_ptr<Discovery>;
    using NotifyCallBack = std::function<void(const std::string& key,const std::string& value)>;
    Discovery(const std::string& host,const std::string& basedir,
    const NotifyCallBack put_cb,const NotifyCallBack del_cb):
    _client(std::make_shared<etcd::Client>(host)),
    _put_cb(put_cb),_del_cb(del_cb)
    {
        auto resp = _client->ls(basedir).get();
        if (resp.is_ok() == false)
        {
            LOG_ERROR("获取数据失败,{}\n",resp.error_message());
        }
        size_t sz = resp.keys().size();
        for (int i = 0; i < sz; i++)
        {
            if(_put_cb) _put_cb(resp.key(i),resp.value(i).as_string());
        }
        _watcher = std::make_shared<etcd::Watcher>(*_client,basedir,
        std::bind(&Discovery::callback,this,std::placeholders::_1), true);
        //watcher.Wait();
    }
private:
    void callback(etcd::Response resp)
    {
        if (resp.is_ok() == false)
        {
            LOG_ERROR("收到一个错误事件通知,{}\n",resp.error_message());
            return;
        }
        for (auto const &ev : resp.events())
        {
            if (ev.event_type() == etcd::Event::EventType::PUT)
            {
                if(_put_cb) _put_cb(ev.kv().key(),ev.kv().as_string());
                LOG_DEBUG("新增服务{}-{}\n",ev.kv().key(),ev.kv().as_string());
            }
            else if (ev.event_type() == etcd::Event::EventType::DELETE_)
            {
                if(_del_cb) _del_cb(ev.prev_kv().key(),ev.prev_kv().as_string());
                LOG_DEBUG("删除服务{}-{}\n",ev.prev_kv().key(),ev.prev_kv().as_string());
            }
        }
    }
    std::shared_ptr<etcd::Client> _client;
    std::shared_ptr<etcd::Watcher> _watcher;
    NotifyCallBack _put_cb;
    NotifyCallBack _del_cb;
};
}